Skip to content

[CodeGen][AArch64][FMV] PAC the stub_helper's frame on arm64e #84704

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

jroelofs
Copy link
Contributor

... and apply default function attributes so that the resolver will also be PAC'd (once more arm64e patches land upstream).

@llvmbot llvmbot added clang Clang issues not falling into any other category backend:AArch64 clang:codegen IR generation bugs: mangling, exceptions, etc. labels Mar 10, 2024
@llvmbot
Copy link
Member

llvmbot commented Mar 10, 2024

@llvm/pr-subscribers-backend-aarch64

@llvm/pr-subscribers-clang-codegen

Author: Jon Roelofs (jroelofs)

Changes

... and apply default function attributes so that the resolver will also be PAC'd (once more arm64e patches land upstream).


Full diff: https://github.com/llvm/llvm-project/pull/84704.diff

6 Files Affected:

  • (modified) clang/lib/CodeGen/CodeGenModule.cpp (+12-6)
  • (added) clang/test/CodeGen/attr-target-version-arm64e.c (+58)
  • (modified) llvm/include/llvm/CodeGen/AsmPrinter.h (+9-4)
  • (modified) llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (+2-1)
  • (modified) llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp (+45)
  • (modified) llvm/test/CodeGen/AArch64/ifunc-asm.ll (+16-5)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 967319bdfc4571..dadc76d04c5f6b 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -4365,13 +4365,16 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
   // For cpu_specific, don't create an ifunc yet because we don't know if the
   // cpu_dispatch will be emitted in this translation unit.
   if (getTarget().supportsIFunc() && !FD->isCPUSpecificMultiVersion()) {
-    llvm::Type *ResolverType = llvm::FunctionType::get(
+    llvm::FunctionType *ResolverType = llvm::FunctionType::get(
         llvm::PointerType::get(DeclTy,
                                getTypes().getTargetAddressSpace(FD->getType())),
         false);
-    llvm::Constant *Resolver = GetOrCreateLLVMFunction(
-        MangledName + ".resolver", ResolverType, GlobalDecl{},
-        /*ForVTable=*/false);
+    llvm::Function *Resolver = cast<llvm::Function>(
+        CreateRuntimeFunction(ResolverType, MangledName + ".resolver")
+            .getCallee());
+    llvm::AttrBuilder Attrs(getLLVMContext());
+    addDefaultFunctionDefinitionAttributes(Attrs);
+    Resolver->addFnAttrs(Attrs);
     llvm::GlobalIFunc *GIF =
         llvm::GlobalIFunc::create(DeclTy, 0, getMultiversionLinkage(*this, GD),
                                   "", Resolver, &getModule());
@@ -4381,8 +4384,11 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
     return GIF;
   }
 
-  llvm::Constant *Resolver = GetOrCreateLLVMFunction(
-      ResolverName, DeclTy, GlobalDecl{}, /*ForVTable=*/false);
+  llvm::Function *Resolver = cast<llvm::Function>(
+      CreateRuntimeFunction(DeclTy, ResolverName).getCallee());
+  llvm::AttrBuilder Attrs(getLLVMContext());
+  addDefaultFunctionDefinitionAttributes(Attrs);
+  Resolver->addFnAttrs(Attrs);
   assert(isa<llvm::GlobalValue>(Resolver) &&
          "Resolver should be created for the first time");
   SetCommonAttributes(FD, cast<llvm::GlobalValue>(Resolver));
diff --git a/clang/test/CodeGen/attr-target-version-arm64e.c b/clang/test/CodeGen/attr-target-version-arm64e.c
new file mode 100644
index 00000000000000..2deff9a688daaa
--- /dev/null
+++ b/clang/test/CodeGen/attr-target-version-arm64e.c
@@ -0,0 +1,58 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals --include-generated-funcs
+// RUN: %clang_cc1 -triple arm64e-apple-ios -target-feature +ls64 -target-feature +fullfp16 -S -emit-llvm -o - %s | FileCheck %s
+
+int __attribute__((target_version("sha1"))) fmv(void) { return 1; }
+int __attribute__((target_version("default"))) fmv(void) { return 0; }
+int foo() {
+  return fmv();
+}
+
+//.
+// CHECK: @__aarch64_cpu_features = external dso_local global { i64 }
+// CHECK: @fmv.ifunc = weak_odr alias i32 (), ptr @fmv
+// CHECK: @fmv = weak_odr ifunc i32 (), ptr @fmv.resolver
+//.
+// CHECK: Function Attrs: noinline nounwind optnone
+// CHECK-LABEL: define {{[^@]+}}@fmv._Msha1
+// CHECK-SAME: () #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK: Function Attrs: noinline nounwind optnone
+// CHECK-LABEL: define {{[^@]+}}@foo
+// CHECK-SAME: () #[[ATTR1:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CALL:%.*]] = call i32 @fmv()
+// CHECK-NEXT:    ret i32 [[CALL]]
+//
+//
+// CHECK-LABEL: define {{[^@]+}}@fmv.resolver
+// CHECK-SAME: () #[[ATTR2:[0-9]+]] {
+// CHECK-NEXT:  resolver_entry:
+// CHECK-NEXT:    call void @__init_cpu_features_resolver()
+// CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[TMP0]], 2048
+// CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 2048
+// CHECK-NEXT:    [[TMP3:%.*]] = and i1 true, [[TMP2]]
+// CHECK-NEXT:    br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]]
+// CHECK:       resolver_return:
+// CHECK-NEXT:    ret ptr @fmv._Msha1
+// CHECK:       resolver_else:
+// CHECK-NEXT:    ret ptr @fmv.default
+//
+//
+// CHECK: Function Attrs: noinline nounwind optnone
+// CHECK-LABEL: define {{[^@]+}}@fmv.default
+// CHECK-SAME: () #[[ATTR1]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 0
+//
+//.
+// CHECK: attributes #[[ATTR0]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+ls64,+neon" }
+// CHECK: attributes #[[ATTR1]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fullfp16,+ls64" }
+// CHECK: attributes #[[ATTR2]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fullfp16,+ls64" }
+//.
+// CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4}
+// CHECK: [[META1:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"}
+//.
diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index a7fbf4aeb74494..3b7e9c282120f9 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -603,16 +603,21 @@ class AsmPrinter : public MachineFunctionPass {
     return nullptr;
   }
 
+  virtual const MCExpr *
+  emitMachOIfuncLazyPointerInit(const MCSymbolRefExpr *Init) {
+    return Init;
+  }
+
   virtual void emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
                                       MCSymbol *LazyPointer) {
-    llvm_unreachable(
-        "Mach-O IFunc lowering is not yet supported on this target");
+    assert(false &&
+           "Mach-O IFunc lowering is not yet supported on this target");
   }
 
   virtual void emitMachOIFuncStubHelperBody(Module &M, const GlobalIFunc &GI,
                                             MCSymbol *LazyPointer) {
-    llvm_unreachable(
-        "Mach-O IFunc lowering is not yet supported on this target");
+    assert(false &&
+           "Mach-O IFunc lowering is not yet supported on this target");
   }
 
   /// Emit N NOP instructions.
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 0efe7a0e733672..b70221cdec296b 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -2259,7 +2259,8 @@ void AsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) {
   emitAlignment(Align(DL.getPointerSize()));
   OutStreamer->emitLabel(LazyPointer);
   emitVisibility(LazyPointer, GI.getVisibility());
-  OutStreamer->emitValue(MCSymbolRefExpr::create(StubHelper, OutContext), 8);
+  const MCSymbolRefExpr *Init = MCSymbolRefExpr::create(StubHelper, OutContext);
+  OutStreamer->emitValue(emitMachOIfuncLazyPointerInit(Init), 8);
 
   OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection());
 
diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index 4fa719ad67cf33..f191fe3259d270 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -208,6 +208,8 @@ class AArch64AsmPrinter : public AsmPrinter {
     assert(STI);
     return STI;
   }
+  const MCExpr *
+  emitMachOIfuncLazyPointerInit(const MCSymbolRefExpr *Init) override;
   void emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
                               MCSymbol *LazyPointer) override;
   void emitMachOIFuncStubHelperBody(Module &M, const GlobalIFunc &GI,
@@ -1897,6 +1899,15 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
   EmitToStreamer(*OutStreamer, TmpInst);
 }
 
+const MCExpr *
+AArch64AsmPrinter::emitMachOIfuncLazyPointerInit(const MCSymbolRefExpr *Init) {
+  if (TM.getTargetTriple().isArm64e())
+    return AArch64AuthMCExpr::create(Init, /*Disc=*/0, AArch64PACKey::IA,
+                                     /*HasAddressDiversity=*/false, OutContext);
+
+  return Init;
+}
+
 void AArch64AsmPrinter::emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
                                                MCSymbol *LazyPointer) {
   // _ifunc:
@@ -1980,6 +1991,9 @@ void AArch64AsmPrinter::emitMachOIFuncStubHelperBody(Module &M,
   //   ldp	fp, lr, [sp], #16
   //   br	x16
 
+  if (TM.getTargetTriple().isArm64e())
+    OutStreamer->emitInstruction(MCInstBuilder(AArch64::PACIBSP), *STI);
+
   OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
                                    .addReg(AArch64::SP)
                                    .addReg(AArch64::FP)
@@ -2085,6 +2099,37 @@ void AArch64AsmPrinter::emitMachOIFuncStubHelperBody(Module &M,
                                    .addImm(2),
                                *STI);
 
+  if (TM.getTargetTriple().isArm64e()) {
+    //   autibsp
+    //   eor x17, lr, lr, lsl #1
+    //   tbz x17, #62, Lgoodsig
+    //   brk #0xc741
+    // Lgoodsig:
+
+    OutStreamer->emitInstruction(MCInstBuilder(AArch64::AUTIBSP), *STI);
+
+    OutStreamer->emitInstruction(MCInstBuilder(AArch64::EORXrs)
+                                     .addReg(AArch64::X17)
+                                     .addReg(AArch64::LR)
+                                     .addReg(AArch64::LR)
+                                     .addImm(1),
+                                 *STI);
+
+    MCContext &Ctx = OutStreamer->getContext();
+    MCSymbol *GoodSigSym = Ctx.createTempSymbol();
+    const MCExpr *GoodSig = MCSymbolRefExpr::create(GoodSigSym, Ctx);
+    OutStreamer->emitInstruction(MCInstBuilder(AArch64::TBZX)
+                                     .addReg(AArch64::X17)
+                                     .addImm(62)
+                                     .addExpr(GoodSig),
+                                 *STI);
+
+    OutStreamer->emitInstruction(MCInstBuilder(AArch64::BRK).addImm(0xc471),
+                                 *STI);
+
+    OutStreamer->emitLabel(GoodSigSym);
+  }
+
   OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e()
                                                  ? AArch64::BRAAZ
                                                  : AArch64::BR)
diff --git a/llvm/test/CodeGen/AArch64/ifunc-asm.ll b/llvm/test/CodeGen/AArch64/ifunc-asm.ll
index 57fc2f0c9d7f5c..6f0d6f633fd513 100644
--- a/llvm/test/CodeGen/AArch64/ifunc-asm.ll
+++ b/llvm/test/CodeGen/AArch64/ifunc-asm.ll
@@ -1,6 +1,8 @@
 ; RUN: llc -mtriple=arm64-unknown-linux-gnu %s -o - | FileCheck %s --check-prefixes=ELF
-; RUN: llc -mtriple=arm64-apple-darwin %s -o - | FileCheck %s --check-prefix=MACHO
-; RUN: llc -mtriple=arm64-apple-darwin %s -global-isel -o - | FileCheck %s --check-prefix=MACHO
+; RUN: llc -mtriple=arm64-apple-darwin %s -o - | FileCheck %s --check-prefixes=MACHO,ARM64
+; RUN: llc -mtriple=arm64-apple-darwin %s -global-isel -o - | FileCheck %s --check-prefixes=MACHO,ARM64
+; RUN: llc -mtriple=arm64e-apple-darwin %s -o - | FileCheck %s --check-prefixes=MACHO,PAUTH
+; RUN: llc -mtriple=arm64e-apple-darwin %s -global-isel -o - | FileCheck %s --check-prefixes=MACHO,PAUTH
 
 define internal ptr @the_resolver() {
 entry:
@@ -21,7 +23,8 @@ entry:
 ; MACHO:           .section __DATA,__data
 ; MACHO-NEXT:      .p2align 3, 0x0
 ; MACHO-NEXT:  _global_ifunc.lazy_pointer:
-; MACHO-NEXT:      .quad _global_ifunc.stub_helper
+; ARM64-NEXT:      .quad _global_ifunc.stub_helper{{$}}
+; PAUTH-NEXT:      .quad _global_ifunc.stub_helper@AUTH(ia,0)
 
 ; MACHO:           .section __TEXT,__text,regular,pure_instructions
 ; MACHO-NEXT:      .globl _global_ifunc
@@ -30,9 +33,11 @@ entry:
 ; MACHO-NEXT:      adrp    x16, _global_ifunc.lazy_pointer@GOTPAGE
 ; MACHO-NEXT:      ldr     x16, [x16, _global_ifunc.lazy_pointer@GOTPAGEOFF]
 ; MACHO-NEXT:      ldr     x16, [x16]
-; MACHO-NEXT:      br      x16
+; ARM64-NEXT:      br      x16
+; PAUTH-NEXT:      braaz   x16
 ; MACHO-NEXT:      .p2align        2
 ; MACHO-NEXT:  _global_ifunc.stub_helper:
+; PAUTH-NEXT:      pacibsp
 ; MACHO-NEXT:      stp     x29, x30, [sp, #-16]!
 ; MACHO-NEXT:      mov     x29, sp
 ; MACHO-NEXT:      stp     x1, x0, [sp, #-16]!
@@ -57,7 +62,13 @@ entry:
 ; MACHO-NEXT:      ldp     x3, x2, [sp], #16
 ; MACHO-NEXT:      ldp     x1, x0, [sp], #16
 ; MACHO-NEXT:      ldp     x29, x30, [sp], #16
-; MACHO-NEXT:      br      x16
+; PAUTH-NEXT:      autibsp
+; PAUTH-NEXT:      eor     x17, x30, x30, lsl #1
+; PAUTH-NEXT:      tbz     x17, #62, [[GOOD_SIG:Ltmp[0-9]+]]
+; PAUTH-NEXT:      brk     #0xc471
+; PAUTH-NEXT: [[GOOD_SIG]]:
+; ARM64-NEXT:      br      x16
+; PAUTH-NEXT:      braaz   x16
 
 
 @weak_ifunc = weak ifunc i32 (i32), ptr @the_resolver

@llvmbot
Copy link
Member

llvmbot commented Mar 10, 2024

@llvm/pr-subscribers-clang

Author: Jon Roelofs (jroelofs)

Changes

... and apply default function attributes so that the resolver will also be PAC'd (once more arm64e patches land upstream).


Full diff: https://github.com/llvm/llvm-project/pull/84704.diff

6 Files Affected:

  • (modified) clang/lib/CodeGen/CodeGenModule.cpp (+12-6)
  • (added) clang/test/CodeGen/attr-target-version-arm64e.c (+58)
  • (modified) llvm/include/llvm/CodeGen/AsmPrinter.h (+9-4)
  • (modified) llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (+2-1)
  • (modified) llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp (+45)
  • (modified) llvm/test/CodeGen/AArch64/ifunc-asm.ll (+16-5)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 967319bdfc4571..dadc76d04c5f6b 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -4365,13 +4365,16 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
   // For cpu_specific, don't create an ifunc yet because we don't know if the
   // cpu_dispatch will be emitted in this translation unit.
   if (getTarget().supportsIFunc() && !FD->isCPUSpecificMultiVersion()) {
-    llvm::Type *ResolverType = llvm::FunctionType::get(
+    llvm::FunctionType *ResolverType = llvm::FunctionType::get(
         llvm::PointerType::get(DeclTy,
                                getTypes().getTargetAddressSpace(FD->getType())),
         false);
-    llvm::Constant *Resolver = GetOrCreateLLVMFunction(
-        MangledName + ".resolver", ResolverType, GlobalDecl{},
-        /*ForVTable=*/false);
+    llvm::Function *Resolver = cast<llvm::Function>(
+        CreateRuntimeFunction(ResolverType, MangledName + ".resolver")
+            .getCallee());
+    llvm::AttrBuilder Attrs(getLLVMContext());
+    addDefaultFunctionDefinitionAttributes(Attrs);
+    Resolver->addFnAttrs(Attrs);
     llvm::GlobalIFunc *GIF =
         llvm::GlobalIFunc::create(DeclTy, 0, getMultiversionLinkage(*this, GD),
                                   "", Resolver, &getModule());
@@ -4381,8 +4384,11 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
     return GIF;
   }
 
-  llvm::Constant *Resolver = GetOrCreateLLVMFunction(
-      ResolverName, DeclTy, GlobalDecl{}, /*ForVTable=*/false);
+  llvm::Function *Resolver = cast<llvm::Function>(
+      CreateRuntimeFunction(DeclTy, ResolverName).getCallee());
+  llvm::AttrBuilder Attrs(getLLVMContext());
+  addDefaultFunctionDefinitionAttributes(Attrs);
+  Resolver->addFnAttrs(Attrs);
   assert(isa<llvm::GlobalValue>(Resolver) &&
          "Resolver should be created for the first time");
   SetCommonAttributes(FD, cast<llvm::GlobalValue>(Resolver));
diff --git a/clang/test/CodeGen/attr-target-version-arm64e.c b/clang/test/CodeGen/attr-target-version-arm64e.c
new file mode 100644
index 00000000000000..2deff9a688daaa
--- /dev/null
+++ b/clang/test/CodeGen/attr-target-version-arm64e.c
@@ -0,0 +1,58 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals --include-generated-funcs
+// RUN: %clang_cc1 -triple arm64e-apple-ios -target-feature +ls64 -target-feature +fullfp16 -S -emit-llvm -o - %s | FileCheck %s
+
+int __attribute__((target_version("sha1"))) fmv(void) { return 1; }
+int __attribute__((target_version("default"))) fmv(void) { return 0; }
+int foo() {
+  return fmv();
+}
+
+//.
+// CHECK: @__aarch64_cpu_features = external dso_local global { i64 }
+// CHECK: @fmv.ifunc = weak_odr alias i32 (), ptr @fmv
+// CHECK: @fmv = weak_odr ifunc i32 (), ptr @fmv.resolver
+//.
+// CHECK: Function Attrs: noinline nounwind optnone
+// CHECK-LABEL: define {{[^@]+}}@fmv._Msha1
+// CHECK-SAME: () #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK: Function Attrs: noinline nounwind optnone
+// CHECK-LABEL: define {{[^@]+}}@foo
+// CHECK-SAME: () #[[ATTR1:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CALL:%.*]] = call i32 @fmv()
+// CHECK-NEXT:    ret i32 [[CALL]]
+//
+//
+// CHECK-LABEL: define {{[^@]+}}@fmv.resolver
+// CHECK-SAME: () #[[ATTR2:[0-9]+]] {
+// CHECK-NEXT:  resolver_entry:
+// CHECK-NEXT:    call void @__init_cpu_features_resolver()
+// CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[TMP0]], 2048
+// CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 2048
+// CHECK-NEXT:    [[TMP3:%.*]] = and i1 true, [[TMP2]]
+// CHECK-NEXT:    br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]]
+// CHECK:       resolver_return:
+// CHECK-NEXT:    ret ptr @fmv._Msha1
+// CHECK:       resolver_else:
+// CHECK-NEXT:    ret ptr @fmv.default
+//
+//
+// CHECK: Function Attrs: noinline nounwind optnone
+// CHECK-LABEL: define {{[^@]+}}@fmv.default
+// CHECK-SAME: () #[[ATTR1]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 0
+//
+//.
+// CHECK: attributes #[[ATTR0]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+ls64,+neon" }
+// CHECK: attributes #[[ATTR1]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fullfp16,+ls64" }
+// CHECK: attributes #[[ATTR2]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fullfp16,+ls64" }
+//.
+// CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4}
+// CHECK: [[META1:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"}
+//.
diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index a7fbf4aeb74494..3b7e9c282120f9 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -603,16 +603,21 @@ class AsmPrinter : public MachineFunctionPass {
     return nullptr;
   }
 
+  virtual const MCExpr *
+  emitMachOIfuncLazyPointerInit(const MCSymbolRefExpr *Init) {
+    return Init;
+  }
+
   virtual void emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
                                       MCSymbol *LazyPointer) {
-    llvm_unreachable(
-        "Mach-O IFunc lowering is not yet supported on this target");
+    assert(false &&
+           "Mach-O IFunc lowering is not yet supported on this target");
   }
 
   virtual void emitMachOIFuncStubHelperBody(Module &M, const GlobalIFunc &GI,
                                             MCSymbol *LazyPointer) {
-    llvm_unreachable(
-        "Mach-O IFunc lowering is not yet supported on this target");
+    assert(false &&
+           "Mach-O IFunc lowering is not yet supported on this target");
   }
 
   /// Emit N NOP instructions.
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 0efe7a0e733672..b70221cdec296b 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -2259,7 +2259,8 @@ void AsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) {
   emitAlignment(Align(DL.getPointerSize()));
   OutStreamer->emitLabel(LazyPointer);
   emitVisibility(LazyPointer, GI.getVisibility());
-  OutStreamer->emitValue(MCSymbolRefExpr::create(StubHelper, OutContext), 8);
+  const MCSymbolRefExpr *Init = MCSymbolRefExpr::create(StubHelper, OutContext);
+  OutStreamer->emitValue(emitMachOIfuncLazyPointerInit(Init), 8);
 
   OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection());
 
diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index 4fa719ad67cf33..f191fe3259d270 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -208,6 +208,8 @@ class AArch64AsmPrinter : public AsmPrinter {
     assert(STI);
     return STI;
   }
+  const MCExpr *
+  emitMachOIfuncLazyPointerInit(const MCSymbolRefExpr *Init) override;
   void emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
                               MCSymbol *LazyPointer) override;
   void emitMachOIFuncStubHelperBody(Module &M, const GlobalIFunc &GI,
@@ -1897,6 +1899,15 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
   EmitToStreamer(*OutStreamer, TmpInst);
 }
 
+const MCExpr *
+AArch64AsmPrinter::emitMachOIfuncLazyPointerInit(const MCSymbolRefExpr *Init) {
+  if (TM.getTargetTriple().isArm64e())
+    return AArch64AuthMCExpr::create(Init, /*Disc=*/0, AArch64PACKey::IA,
+                                     /*HasAddressDiversity=*/false, OutContext);
+
+  return Init;
+}
+
 void AArch64AsmPrinter::emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
                                                MCSymbol *LazyPointer) {
   // _ifunc:
@@ -1980,6 +1991,9 @@ void AArch64AsmPrinter::emitMachOIFuncStubHelperBody(Module &M,
   //   ldp	fp, lr, [sp], #16
   //   br	x16
 
+  if (TM.getTargetTriple().isArm64e())
+    OutStreamer->emitInstruction(MCInstBuilder(AArch64::PACIBSP), *STI);
+
   OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
                                    .addReg(AArch64::SP)
                                    .addReg(AArch64::FP)
@@ -2085,6 +2099,37 @@ void AArch64AsmPrinter::emitMachOIFuncStubHelperBody(Module &M,
                                    .addImm(2),
                                *STI);
 
+  if (TM.getTargetTriple().isArm64e()) {
+    //   autibsp
+    //   eor x17, lr, lr, lsl #1
+    //   tbz x17, #62, Lgoodsig
+    //   brk #0xc741
+    // Lgoodsig:
+
+    OutStreamer->emitInstruction(MCInstBuilder(AArch64::AUTIBSP), *STI);
+
+    OutStreamer->emitInstruction(MCInstBuilder(AArch64::EORXrs)
+                                     .addReg(AArch64::X17)
+                                     .addReg(AArch64::LR)
+                                     .addReg(AArch64::LR)
+                                     .addImm(1),
+                                 *STI);
+
+    MCContext &Ctx = OutStreamer->getContext();
+    MCSymbol *GoodSigSym = Ctx.createTempSymbol();
+    const MCExpr *GoodSig = MCSymbolRefExpr::create(GoodSigSym, Ctx);
+    OutStreamer->emitInstruction(MCInstBuilder(AArch64::TBZX)
+                                     .addReg(AArch64::X17)
+                                     .addImm(62)
+                                     .addExpr(GoodSig),
+                                 *STI);
+
+    OutStreamer->emitInstruction(MCInstBuilder(AArch64::BRK).addImm(0xc471),
+                                 *STI);
+
+    OutStreamer->emitLabel(GoodSigSym);
+  }
+
   OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e()
                                                  ? AArch64::BRAAZ
                                                  : AArch64::BR)
diff --git a/llvm/test/CodeGen/AArch64/ifunc-asm.ll b/llvm/test/CodeGen/AArch64/ifunc-asm.ll
index 57fc2f0c9d7f5c..6f0d6f633fd513 100644
--- a/llvm/test/CodeGen/AArch64/ifunc-asm.ll
+++ b/llvm/test/CodeGen/AArch64/ifunc-asm.ll
@@ -1,6 +1,8 @@
 ; RUN: llc -mtriple=arm64-unknown-linux-gnu %s -o - | FileCheck %s --check-prefixes=ELF
-; RUN: llc -mtriple=arm64-apple-darwin %s -o - | FileCheck %s --check-prefix=MACHO
-; RUN: llc -mtriple=arm64-apple-darwin %s -global-isel -o - | FileCheck %s --check-prefix=MACHO
+; RUN: llc -mtriple=arm64-apple-darwin %s -o - | FileCheck %s --check-prefixes=MACHO,ARM64
+; RUN: llc -mtriple=arm64-apple-darwin %s -global-isel -o - | FileCheck %s --check-prefixes=MACHO,ARM64
+; RUN: llc -mtriple=arm64e-apple-darwin %s -o - | FileCheck %s --check-prefixes=MACHO,PAUTH
+; RUN: llc -mtriple=arm64e-apple-darwin %s -global-isel -o - | FileCheck %s --check-prefixes=MACHO,PAUTH
 
 define internal ptr @the_resolver() {
 entry:
@@ -21,7 +23,8 @@ entry:
 ; MACHO:           .section __DATA,__data
 ; MACHO-NEXT:      .p2align 3, 0x0
 ; MACHO-NEXT:  _global_ifunc.lazy_pointer:
-; MACHO-NEXT:      .quad _global_ifunc.stub_helper
+; ARM64-NEXT:      .quad _global_ifunc.stub_helper{{$}}
+; PAUTH-NEXT:      .quad _global_ifunc.stub_helper@AUTH(ia,0)
 
 ; MACHO:           .section __TEXT,__text,regular,pure_instructions
 ; MACHO-NEXT:      .globl _global_ifunc
@@ -30,9 +33,11 @@ entry:
 ; MACHO-NEXT:      adrp    x16, _global_ifunc.lazy_pointer@GOTPAGE
 ; MACHO-NEXT:      ldr     x16, [x16, _global_ifunc.lazy_pointer@GOTPAGEOFF]
 ; MACHO-NEXT:      ldr     x16, [x16]
-; MACHO-NEXT:      br      x16
+; ARM64-NEXT:      br      x16
+; PAUTH-NEXT:      braaz   x16
 ; MACHO-NEXT:      .p2align        2
 ; MACHO-NEXT:  _global_ifunc.stub_helper:
+; PAUTH-NEXT:      pacibsp
 ; MACHO-NEXT:      stp     x29, x30, [sp, #-16]!
 ; MACHO-NEXT:      mov     x29, sp
 ; MACHO-NEXT:      stp     x1, x0, [sp, #-16]!
@@ -57,7 +62,13 @@ entry:
 ; MACHO-NEXT:      ldp     x3, x2, [sp], #16
 ; MACHO-NEXT:      ldp     x1, x0, [sp], #16
 ; MACHO-NEXT:      ldp     x29, x30, [sp], #16
-; MACHO-NEXT:      br      x16
+; PAUTH-NEXT:      autibsp
+; PAUTH-NEXT:      eor     x17, x30, x30, lsl #1
+; PAUTH-NEXT:      tbz     x17, #62, [[GOOD_SIG:Ltmp[0-9]+]]
+; PAUTH-NEXT:      brk     #0xc471
+; PAUTH-NEXT: [[GOOD_SIG]]:
+; ARM64-NEXT:      br      x16
+; PAUTH-NEXT:      braaz   x16
 
 
 @weak_ifunc = weak ifunc i32 (i32), ptr @the_resolver

// CHECK: resolver_return:
// CHECK-NEXT: ret ptr @fmv._Msha1
// CHECK: resolver_else:
// CHECK-NEXT: ret ptr @fmv.default
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The machinery to sign these hasn't been upstreamed yet, but they'll be e.g. @fmv.default.pauth when that happens.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks useful for arm64 as well, could you reveal more details on the machinery and approach to PAC resolver?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thing that's missing is this:

https://github.com/apple/llvm-project/blob/970b6231f607e211c23e15a582572e6f18f4e6b2/clang/include/clang/CodeGen/CodeGenABITypes.h#L122-L126

along with this hunk:

--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -2893,7 +2893,11 @@ static void CreateMultiVersionResolverReturn(CodeGenModule &CGM,
                                              llvm::Function *FuncToReturn,
                                              bool SupportsIFunc) {
   if (SupportsIFunc) {
-    Builder.CreateRet(FuncToReturn);
+    llvm::Constant *Fn = FuncToReturn;
+    if (CGM.getContext().getTargetInfo().getTriple().isArm64e())
+      Fn = CGM.getConstantSignedPointer(
+          Fn, 0, nullptr, llvm::Constant::getNullValue(CGM.SizeTy));
+    Builder.CreateRet(Fn);
     return;
   }

This arranges for the resolver to return signed function pointers. There is no difference for arm64(non-e).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@asl the check in the hunk above should be generalized for ELF, and only turned on with -fptrauth-calls. I wasn't sure how to get a QualType here though, which would be needed to get the CGPointerAuthInfo that this would make the check on. Not sure if it's reasonable to "invent" one that's close enough, e.g. for void (*fn_ptr)(void); or something.

@asl
Copy link
Collaborator

asl commented Mar 14, 2024

Tagging @kovdan01

Can the triple checks be generalized to checking about pauth-enabled subtarget feature? This way everything would work for ELF platforms eventually.

@kovdan01
Copy link
Contributor

Can the triple checks be generalized to checking about pauth-enabled subtarget feature? This way everything would work for ELF platforms eventually.

@asl Since I'm not sure how particularly ifuncs should be handled, here are two answers for two different cases.

If we need just to check that pauth target feature is enabled, we can use TM.getTargetFeatureString() and see if it contains +pauth.

If the ifunc-related behavior is dependent on -fptrauth-calls (implicitly enabled on apple arm64e) and should not be enabled when, say, only -fptrauth-returns is used (in both cases the target feature string contains +pauth), on ELF we can add a check against (platform,version) tuple defining the ABI after #85236 is merged.

@jroelofs
Copy link
Contributor Author

jroelofs commented Mar 14, 2024

Can the triple checks be generalized to checking about pauth-enabled subtarget feature? This way everything would work for ELF platforms eventually.

These are admittedly a bit of a hack, since we don't have a Function to look at the attributes on when we're in that part of the AsmPrinter. But that said, the ones in the AsmPrinter are all Mach-O-specific: they "manually" implement what the dynamic linker would do on an ELF platform, so generalizing them won't help ELF platforms.

@asl Since I'm not sure how particularly ifuncs should be handled, here are two answers for two different cases.

If we need just to check that pauth target feature is enabled, we can use TM.getTargetFeatureString() and see if it contains +pauth.

If the ifunc-related behavior is dependent on -fptrauth-calls (implicitly enabled on apple arm64e) and should not be enabled when, say, only -fptrauth-returns is used (in both cases the target feature string contains +pauth), on ELF we can add a check against (platform,version) tuple defining the ABI after #85236 is merged.

The change to add the default attributes should cover whether the resolver gets -fptrauth-returns.

For -fptrauth-calls on the other hand you will need some cooperation with the dynamic linker on ELF targets, since on those platforms you'll need to coordinate with the implementation of .type global_ifunc,@gnu_indirect_function to decide whether the resolver should sign the returned pointer and with what key.

@jroelofs jroelofs requested a review from TNorthover March 14, 2024 21:37
@@ -2085,6 +2099,37 @@ void AArch64AsmPrinter::emitMachOIFuncStubHelperBody(Module &M,
.addImm(2),
*STI);

if (TM.getTargetTriple().isArm64e()) {
// autibsp
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leave the tail-call checking for the general tail-call checking patches, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a PR up for that that I should tack this bit onto the end of?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is not, but send me your patch and I'll tack it onto the relevant commit (and split the tail-call check emission into a helper)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link

github-actions bot commented Jul 22, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:AArch64 clang:codegen IR generation bugs: mangling, exceptions, etc. clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants